#include <rtthread.h>
#include <drv_gpio.h>
#include "rtdbg.h"
#include <rtdevice.h>
#include "rtthread.h"
#include <drv_spi.h>
#include "25q64.h"

#define FLASH_25Q64_SPI     "spi2"
#define FLASH_25Q64_SPI_DEVICE     "spi20"
#define FLASH_25Q64_SPI_DEVICE_CS_PIN   GET_PIN(B, 12)


#define FLASH_PARAMETER       RT_NULL
#ifndef FLASH_THREAD_STACK_SIZE
#define FLASH_THREAD_STACK_SIZE      1024
#endif
#ifndef FLASH_PRIORITY
#define FLASH_PRIORITY        10  
#endif           


rt_thread_t flash_25q64_thread;

static struct rt_spi_device *spi_dev_flash_25q64;

static int rt_hw_flash_25q64_config(void)
{
    __HAL_RCC_GPIOB_CLK_ENABLE();
    
    if (RT_EOK != rt_hw_spi_device_attach(FLASH_25Q64_SPI, FLASH_25Q64_SPI_DEVICE, FLASH_25Q64_SPI_DEVICE_CS_PIN))
    {
        LOG_E("Failed to attach the FLASH_25Q64_SPI_DEVICE.");
        return -RT_ERROR;
    }

    spi_dev_flash_25q64 = (struct rt_spi_device *)rt_device_find(FLASH_25Q64_SPI_DEVICE);
    if(spi_dev_flash_25q64 == RT_NULL) 
    {
        LOG_E("FLASH_25Q64_SPI_DEVICE no find");
        return -RT_ERROR;
    }

    /* config spi */
    {
        struct rt_spi_configuration cfg = {0};
        cfg.data_width = 8;
        cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
        cfg.max_hz = 18 * 1000 * 1000; /* 18M,SPI max 18MHz,lcd 4-wire spi */

        rt_spi_configure(spi_dev_flash_25q64, &cfg);
    }
    return RT_EOK;
}
INIT_APP_EXPORT (rt_hw_flash_25q64_config);

rt_uint8_t spi_read_write_byte(rt_uint8_t dat)
{
    rt_uint8_t recv_dat = 0;
    //通过SPI4发送一个字节数据
    //读取并返回在SPI读取到的单字节数据
    rt_spi_send_then_recv(spi_dev_flash_25q64, &dat, 1, &recv_dat, 1);

    return recv_dat;
}

rt_uint16_t flash_25q64_readID(void)
{
    rt_uint8_t cmd_buf[4] = {HG25Q64_CMD_READ_MANUFACTURER_ID, 0x00, 0x00, 0x00};
    rt_uint8_t id_buf[2];
    rt_err_t result;
    
    result = rt_spi_send_then_recv(spi_dev_flash_25q64, cmd_buf, 4, id_buf, 2);
    if (result == RT_EOK)
    {
        LOG_I("Manufacturer ID: 0x%02X, Device ID: 0x%02X", id_buf[0], id_buf[1]);
    }
    return (id_buf[0] << 8) | id_buf[1];
}
INIT_FS_EXPORT(flash_25q64_readID);

static inline void flash_25q64_write_enable(void)
{
    uint8_t cmd = HG25Q64_CMD_WRITE_ENABLE;
    rt_spi_send(spi_dev_flash_25q64, &cmd, 1);
}

void flash_25q64_wait_busy(void)
{
    rt_uint8_t byte = 0;
    do
     {
        //发送指令05h
        byte = spi_read_write_byte(HG25Q64_CMD_READ_STATUS_REG1);
     //判断BUSY位是否为1 如果为1说明在忙，重新读写BUSY位直到为0
     }while( ( byte & 0x01 ) == 1 );
}

/**********************************************************
 * 函 数 名 flash_25q64_sector
 * 函 数 功 能：擦除一个扇区
 * 传 入 参 数：addr=擦除的扇区号
 * 函 数 返 回：无
 * 作       者：LC
 * 备       注：addr=擦除的扇区号，范围=0~15
**********************************************************/
void flash_25q64_sector(uint32_t addr)
{
    //计算扇区号，一个扇区4KB=4096
    addr *= 4096;
    flash_25q64_write_enable();
    flash_25q64_wait_busy();     //判断忙，如果忙则一直等待
    rt_uint8_t buf[4] = {HG25Q64_CMD_SECTOR_ERASE_4K, (addr)>>16, (addr)>>8, addr};
    rt_spi_send(spi_dev_flash_25q64, buf, sizeof(buf));
    //等待擦除完成
    flash_25q64_wait_busy();
}
/**********************************************************
 * 函 数 名 flash_25q64_write
 * 函 数 功 能：
 * 传 入 参 数：addr=扇区号
 * 函 数 返 回：无
 * 作       者：LC
 * 备       注：addr=扇区号，范围=0~15
**********************************************************/
rt_int16_t flash_25q64_write(rt_uint8_t *buffer, rt_uint32_t addr, rt_uint16_t numbyte)
{
    rt_err_t result;
    // 参数检查
    if (buffer == RT_NULL) {
        LOG_E("flash_25q64_write: buffer is NULL");
        return -RT_ERROR;
    }
    
    if (numbyte == 0) {
        LOG_E("flash_25q64_write: numbyte is 0");
        return -RT_ERROR;
    }
    // 先擦除
    flash_25q64_sector(addr);
    // 忙检测
    flash_25q64_wait_busy();
    // 写使能
    flash_25q64_write_enable();
    // 忙检测
    flash_25q64_wait_busy();

    //计算扇区号，一个扇区4KB=4096
    addr *= 4096;
    // 准备写入命令和地址
    // 使用 PAGE PROGRAM 命令，不是 SECTOR ERASE!
    rt_uint8_t write_cmd[4] = {
        HG25Q64_CMD_PAGE_PROGRAM,  // 应该是 0x02
        (rt_uint8_t)(addr >> 16),  // 地址字节2
        (rt_uint8_t)(addr >> 8),   // 地址字节1  
        (rt_uint8_t)(addr)         // 地址字节0
    };
    
    // 发送写入命令+地址，然后发送数据
    result = rt_spi_send_then_send(spi_dev_flash_25q64, 
                                  write_cmd, sizeof(write_cmd), 
                                  buffer, numbyte);
    if (result != RT_EOK)
    {
        LOG_E("flash_25q64_write: SPI transfer failed, result=%d", result);
        return -RT_ERROR;
    }
    
    // 忙检测，等待写入完成
    flash_25q64_wait_busy(); 
    return RT_EOK;
}

void flash_25q64_read(rt_uint8_t *buffer_recv, rt_uint32_t addr, rt_uint16_t numbyte)
{
    addr *= 4096;
    //发送指令03h
    //读取数据
    rt_uint8_t cmd_buf[4] = {HG25Q64_CMD_READ_DATA, (addr)>>16, (addr)>>8, addr};
    rt_err_t result;
    
    result = rt_spi_send_then_recv(spi_dev_flash_25q64, cmd_buf, 4, buffer_recv, numbyte);
    if (result != RT_EOK)
    {
        LOG_E("flash_25q64_read error");
    }
}

/************************************************************************************************* */
// 先声明，buf初始化为NULL
flash_storage_t flash_dat[] = {
    {
        .name = "label_temp_set",
        .buf = RT_NULL,  // 初始化为NULL
        .size = 2,
        .current_addr = 0,
        .dirty_flag = RT_FALSE
    },
    {
        .name = "encode_dir_flag", 
        .buf = RT_NULL,  // 初始化为NULL
        .size = 1,
        .current_addr = 1,
        .dirty_flag = RT_FALSE
    },
    {
        .name = "fan_speed", 
        .buf = RT_NULL,  // 初始化为NULL
        .size = 1,
        .current_addr = 2,
        .dirty_flag = RT_FALSE
    }
};

// 初始化函数 - 在系统启动时调用
int flash_storage_init(void)
{
    int i;
    
    for (i = 0; i < sizeof(flash_dat)/sizeof(flash_dat[0]); i++) {
        flash_dat[i].buf = (rt_uint8_t *)rt_malloc(flash_dat[i].size);
        if (flash_dat[i].buf == RT_NULL) {
            rt_kprintf("内存分配失败: %s, 大小: %d\n", flash_dat[i].name, flash_dat[i].size);
            return -RT_ENOMEM;
        }
        
        // 初始化内存为0
        rt_memset(flash_dat[i].buf, 0, flash_dat[i].size);
        rt_kprintf("为 %s 分配了 %d 字节内存\n", flash_dat[i].name, flash_dat[i].size);
    }
    
    // 正确读取和显示数据
    for (i = 0; i < sizeof(flash_dat)/sizeof(flash_dat[0]); i++) {
        flash_25q64_read(flash_dat[i].buf, flash_dat[i].current_addr, flash_dat[i].size);
        
        // 根据实际数据类型正确显示
        if (flash_dat[i].size == 2) {
            // 2字节数据，当作16位整数显示
            rt_uint16_t value = *(rt_uint16_t*)flash_dat[i].buf;
            LOG_D("%s read success, value: %u (0x%04X)", flash_dat[i].name, value, value);
        } else if (flash_dat[i].size == 1) {
            // 1字节数据，当作8位整数显示
            rt_uint8_t value = flash_dat[i].buf[0];
            LOG_D("%s read success, value: %u (0x%02X)", flash_dat[i].name, value, value);
        } else {
            // 其他大小的数据，显示原始字节
            LOG_D("%s read success, raw bytes:", flash_dat[i].name);
            for (int j = 0; j < flash_dat[i].size; j++) {
                rt_kprintf(" 0x%02X", flash_dat[i].buf[j]);
            }
            rt_kprintf("\n");
        }
    }
    
    return RT_EOK;
}
INIT_FS_EXPORT(flash_storage_init);

void flash_25q64_entry(void *param)
{
    // rt_uint8_t buf[2] = {234, 0};
    // rt_uint8_t buf_[2];
    while (1)
    {
        // flash_25q64_write(buf, 0, 2);
        // flash_25q64_read(buf_, 0, 2);
        // LOG_D("buf_:%d, %d", buf_[0], buf_[1]);
        for (int i = 0; i < sizeof(flash_dat)/sizeof(flash_dat[0]); i++) {
            if (flash_dat[i].dirty_flag && flash_dat[i].buf != NULL) {
                // 写入Flash
                if (flash_25q64_write(flash_dat[i].buf, flash_dat[i].current_addr, flash_dat[i].size) == RT_EOK) {
                    // 写入成功，清除脏标志
                    flash_dat[i].dirty_flag = RT_FALSE;
                    rt_kprintf("Saved %s to flash\n", flash_dat[i].name);
                } else {
                    rt_kprintf("Failed to save %s to flash\n", flash_dat[i].name);
                }
            }
        }
        rt_thread_mdelay(1000);
    }
    
}

int flash_25q64_run(void)
{
   flash_25q64_thread = rt_thread_create("flash_thread",
                                        flash_25q64_entry,
                                        FLASH_PARAMETER,
                                        FLASH_THREAD_STACK_SIZE,
                                        FLASH_PRIORITY,
                                        20);

    if (flash_25q64_thread == RT_NULL)
    {
        LOG_E("flash_25q64_thread create error");
        return -1;
    }
    rt_thread_startup(flash_25q64_thread);
    return 0;
}
INIT_APP_EXPORT(flash_25q64_run);
